package ua.lviv.franko.solvers.stressanalysis.oneDimention;

import java.util.ArrayList;
import java.util.List;

import ua.lviv.franko.integration.IFunction1D;
import ua.lviv.franko.integration.VectorFunction1D;
import ua.lviv.franko.integration.VectorFunctionWithoutDerivatives1D;

public class FEElementLinear extends AbstractElement1D {

	public FEElementLinear(EquationParameters eParams, int elNumber, final double left, final double right) {
		super(eParams, elNumber, left, right);
		final double h = right - left;
		baseFunctions = new ArrayList<IFunction1D>();
		baseFunctions.add(new IFunction1D() {

			@Override
			public double calculate(double x) {
				if ((x < left) || (x > right)) {
					return 0.0;
				}
				return (right - x) / h;
			}

			@Override
			public double calculateDerivaty(double x) {

				return -1.0 / h;
			}
		});

		baseFunctions.add(new IFunction1D() {

			@Override
			public double calculate(double x) {
				if ((x < left) || (x > right)) {
					return 0.0;
				}
				return ((x - left) / h);
			}

			@Override
			public double calculateDerivaty(double x) {

				return 1.0 / h;
			}
		});
	}

	@Override
	public double[] calculate(double x, double[] results) {
		double v1 = baseFunctions.get(0).calculate(x);
		double v2 = baseFunctions.get(1).calculate(x);
		return new double[] { v1 * results[3 * elNumber] + v2 * results[3 * (elNumber + 1)], v1 * results[3 * elNumber + 1] + v2 * results[3 * (elNumber + 1) + 1],
				v1 * results[3 * elNumber + 2] + v2 * results[3 * (elNumber + 1) + 2] };
	}

	@Override
	protected ElementMatrix calculateSmallData(int i, int j) {
		ElementMatrix res = new ElementMatrix(this.getNodesNumbers());

		final IFunction1D fi = baseFunctions.get(i);
		final IFunction1D fj = baseFunctions.get(j);

		double[] tmp = gau.integrate(left, right, new VectorFunction1D() {

			@Override
			public double[] calculate(double x) {
				double fiDer = fi.calculateDerivaty(x);
				double fjDer = fj.calculateDerivaty(x);
				double fiVal = fi.calculate(x);
				double fjVal = fj.calculate(x);
				double a1 = eParams.getA1().calculate(x);
				double k1 = eParams.getK1().calculate(x);
				return new double[] {
						// first row
						kKk1 / a1 * fiDer * fjDer + a1 * k1 * k1 * kKk2 * fiVal * fjVal, kKk1 / a1 * k1 * fjVal * fiDer - k1 * kKk2 * fjDer * fiVal,
						-a1 * k1 * kKk2 * fiVal * fjVal,
						// second row
						-kKk2 * k1 * fjVal * fiDer + k1 * kKk1 * fjDer * fiVal, kKk2 / a1 * fjDer * fiDer + a1 * k1 * k1 * kKk1 * fiVal * fjVal, kKk2 * fjVal * fiDer,
						// third row
						-a1 * kKk2 * k1 * fiVal * fjVal, kKk2 * fjDer * fiVal, kKk3 / a1 * fjDer * fiDer + a1 * kKk2 * fiVal * fjVal };
			}

			@Override
			public double[] calculateDerivaty(double x) {

				return null;
			}

			@Override
			public int vectorSize() {
				return 9;
			}
		});

//		for (int k = 0; k < tmp.length; k++) {
//			System.err.print(tmp[k] + "\t");
//		}
//		System.err.println();
		for (int k = 0; k < 3; k++) {
			res.matrix[k][0] = tmp[3 * k];
			res.matrix[k][1] = tmp[3 * k + 1];
			res.matrix[k][2] = tmp[3 * k + 2];
		}
		// right hand side
		res.vector = gau.integrate(left, right, new VectorFunction1D() {

			@Override
			public double[] calculate(double x) {
				double fiVal = fi.calculate(x);
				double h = eParams.getH() / 2.0;
				double k1 = eParams.getK1().calculate(x);

				double rho1Val = rho1.calculate(x);
				double rho3Val = rho3.calculate(x);
				double mu1Val = mu1.calculate(x);

				double sigma11Minus = eParams.getSigma11Minus().calculate(x);
				double sigma11Plus = eParams.getSigma11Plus().calculate(x);

				double sigma13Minus = eParams.getSigma13Minus().calculate(x);
				double sigma13Plus = eParams.getSigma13Plus().calculate(x);

//				double sigma33Minus = eParams.getSigma33Minus().calculate(x);
//				double sigma33Plus = eParams.getSigma33Plus().calculate(x);
//
//				return new double[] { fiVal * ((1 + k1 * h) * sigma13Plus + (1 - k1 * h) * sigma13Minus + rho1Val),
//						fiVal * ((1 + k1 * h) * sigma33Plus + (1 - k1 * h) * sigma33Minus + rho3Val),
//						fiVal * (((1 + k1 * h) * sigma11Plus - (1 - k1 * h) * sigma11Minus) * h + mu1Val),
//
//				};
				return new double[] { fiVal * ((1 + k1 * h) * sigma11Plus + (1 - k1 * h) * sigma11Minus + rho1Val),
						fiVal * ((1 + k1 * h) * sigma13Plus + (1 - k1 * h) * sigma13Minus + rho3Val),
						fiVal * (((1 + k1 * h) * sigma11Plus - (1 - k1 * h) * sigma11Minus) * h + mu1Val),

				};
			}

			@Override
			public double[] calculateDerivaty(double x) {

				return null;
			}

			@Override
			public int vectorSize() {

				return 3;
			}
		});

		return res;
	}

	@Override
	public List<Integer> getNodesNumbers() {
		List<Integer> result = new ArrayList<Integer>();
		result.add(elNumber);
		result.add(elNumber + 1);
		return result;
	}

	@Override
	protected double[] calculateSmallUpdatedVector(int i, final EquationParameters parameters) {
		final IFunction1D fi = baseFunctions.get(i);
		return gau.integrate(left, right, new VectorFunctionWithoutDerivatives1D(3) {
			
			@Override
			public double[] calculate(double x) {
				double fiVal = fi.calculate(x);
				double h = parameters.getH() / 2.0;
				double k1 = parameters.getK1().calculate(x);
				
				double rho1Val = rho1.calculate(x);
				double rho3Val = rho3.calculate(x);
				double mu1Val = mu1.calculate(x);

				double sigma11Minus = parameters.getSigma11Minus().calculate(x);
				double sigma11Plus = parameters.getSigma11Plus().calculate(x);

				double sigma13Minus = parameters.getSigma13Minus().calculate(x);
				double sigma13Plus = parameters.getSigma13Plus().calculate(x);

				double sigma33Minus = parameters.getSigma33Minus().calculate(x);
				double sigma33Plus = parameters.getSigma33Plus().calculate(x);

				return new double[] { fiVal * ((1 + k1 * h) * sigma13Plus + (1 - k1 * h) * sigma13Minus + rho1Val),
						fiVal * ((1 + k1 * h) * sigma33Plus + (1 - k1 * h) * sigma33Minus + rho3Val),
						fiVal * (((1 + k1 * h) * sigma11Plus - (1 - k1 * h) * sigma11Minus) * h + mu1Val)
				};
			}
		});
	}

}
